package com.game.doudizhu.core;

import com.game.doudizhu.core.AIModelPersistence;
import com.game.doudizhu.core.CardUtil;
import com.game.doudizhu.model.Card;
import com.game.doudizhu.model.GameState;
import com.game.doudizhu.util.CardPatternUtil;

import java.util.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AIStrategy {
    private static final Logger logger = LoggerFactory.getLogger(AIStrategy.class);
    private static AIModelPersistence.AIModel aiModel = null;
    private static long lastUpdateTime = 0;
    private static final long UPDATE_INTERVAL = 5000; // 每5秒更新一次策略

    // 游戏阶段常量
    public static final int EARLY_GAME = 1;   // 手牌数 > 10
    public static final int MID_GAME = 2;     // 5 < 手牌数 <= 10
    public static final int LATE_GAME = 3;    // 手牌数 <= 5

    static {
        loadAIModel();
    }

    private static void loadAIModel() {
        aiModel = AIModelPersistence.loadModel();
    }

    // 获取游戏阶段
    public static int getGameStage(int cardCount) {
        if (cardCount > 10) return EARLY_GAME;
        if (cardCount > 5) return MID_GAME;
        return LATE_GAME;
    }

    // 叫分策略
    public static int decideBid(List<Card> cards, int currentMaxBid) {
        // 更新策略
        updateStrategyIfNeeded();
        
        int strength = calculateHandStrength(cards);
        logger.debug("AI手牌强度: {}", strength);

        // 使用学习到的叫分模式
        String strengthKey = String.format("STRENGTH_%d", (strength / 10) * 10);
        if (aiModel.bidPatterns != null && aiModel.bidPatterns.containsKey(strengthKey)) {
            double successRate = aiModel.bidPatterns.get(strengthKey);
            logger.debug("该手牌强度区间的历史成功率: {}", successRate);

            // 根据历史成功率调整叫分策略
            if (successRate > 0.7) {
                return currentMaxBid < 3 ? 3 : 0;
            } else if (successRate > 0.5) {
                return currentMaxBid < 2 ? 2 : 0;
            } else if (successRate > 0.3) {
                return currentMaxBid < 1 ? 1 : 0;
            }
            return 0;
        }

        // 如果没有历史数据，使用基础策略
        if (strength >= 100) return currentMaxBid < 3 ? 3 : 0;
        if (strength >= 85) return currentMaxBid < 2 ? 2 : 0;
        if (strength >= 70) return currentMaxBid < 1 ? 1 : 0;
        return 0;
    }

    // 出牌策略
    public static List<Card> decideCards(List<Card> handCards,
                                       List<Card> lastPlayedCards,
                                       boolean isLandlord,
                                       GameState gameState) {
        updateStrategyIfNeeded();
        
        int gameStage = getGameStage(handCards.size());
        int handStrength = calculateHandStrength(handCards);

        // 主动出牌
        if (lastPlayedCards == null || lastPlayedCards.isEmpty()) {
            return findBestLeadingCards(handCards, isLandlord, gameStage, handStrength);
        }

        // 跟牌
        return findBestFollowingCards(handCards, lastPlayedCards, isLandlord, gameStage, gameState, handStrength);
    }

    // 寻找最佳的主动出牌
    private static List<Card> findBestLeadingCards(List<Card> handCards,
                                                  boolean isLandlord,
                                                  int gameStage,
                                                  int handStrength) {
        List<List<Card>> possiblePlays = findAllPossiblePlays(handCards);
        if (possiblePlays.isEmpty()) {
            return Collections.emptyList();
        }

        // 计算每种出牌方案的得分
        Map<List<Card>, Double> playScores = new HashMap<>();
        for (List<Card> play : possiblePlays) {
            double score = evaluatePlay(play, handCards, null, isLandlord, gameStage, handStrength);
            playScores.put(play, score);
        }

        // 根据场上形势调整策略
        adjustStrategyByGameSituation(playScores, isLandlord, gameStage, handStrength);

        return playScores.entrySet().stream()
                .max(Map.Entry.comparingByValue())
                .map(Map.Entry::getKey)
                .orElse(Collections.emptyList());
    }

    // 评估出牌方案
    private static double evaluatePlay(List<Card> play,
                                     List<Card> handCards,
                                     List<Card> lastPlayedCards,
                                     boolean isLandlord,
                                     int gameStage,
                                     int handStrength) {
        double score = 0;
        
        // 基础分数
        score += calculateBaseScore(play);
        
        // 根据剩余牌型评分
        List<Card> remainingCards = new ArrayList<>(handCards);
        remainingCards.removeAll(play);
        score += evaluateRemainingCards(remainingCards);
        
        // 根据游戏阶段调整分数
        score *= getGameStageMultiplier(gameStage);
        
        // 根据身份调整策略
        score *= getRoleMultiplier(isLandlord, handStrength);
        
        // 考虑是否需要压制对手
        if (lastPlayedCards != null) {
            score *= getControlMultiplier(play, lastPlayedCards);
        }
        
        // 新增：考虑出牌的节奏性
        score *= evaluateRhythm(play, remainingCards);
        
        // 新增：考虑牌型的灵活性
        score *= evaluateFlexibility(remainingCards);
        
        // 新增：考虑关键牌的保留
        score *= evaluateKeyCards(play, remainingCards, isLandlord, gameStage);
        
        return score;
    }

    // 计算基础分数
    private static double calculateBaseScore(List<Card> play) {
        double score = 0;
        CardPatternUtil.CardPattern pattern = CardPatternUtil.getPattern(play);
        
        switch (pattern) {
            case ROCKET:
                score = 100;
                break;
            case BOMB:
                score = 80;
                break;
            case STRAIGHT:
                score = play.size() * 12;
                break;
            case STRAIGHT_PAIR:
                score = play.size() * 10;
                break;
            case AIRPLANE:
                score = play.size() * 8;
                break;
            case TRIPLE_WITH_ONE:
            case TRIPLE_WITH_PAIR:
                score = 25;
                break;
            case PAIR:
                score = 15;
                break;
            case SINGLE:
                Card card = play.get(0);
                score = card.getWeight() >= 15 ? 10 : 5; // 2和大小王分数更高
                break;
        }
        
        return score;
    }

    // 评估剩余牌型
    private static double evaluateRemainingCards(List<Card> remainingCards) {
        double score = 0;
        
        // 检查剩余的牌型
        Map<String, List<Card>> rankGroups = CardUtil.groupByRank(remainingCards);
        
        // 评估炸弹
        score += rankGroups.values().stream()
                .filter(group -> group.size() == 4)
                .count() * 50;
        
        // 评估三张
        score += rankGroups.values().stream()
                .filter(group -> group.size() == 3)
                .count() * 30;
        
        // 评估对子
        score += rankGroups.values().stream()
                .filter(group -> group.size() == 2)
                .count() * 15;
        
        // 评估顺子潜力
        score += evaluateStraightPotential(remainingCards);
        
        return score;
    }

    // 评估顺子潜力
    private static double evaluateStraightPotential(List<Card> cards) {
        double score = 0;
        List<Card> sortedCards = new ArrayList<>(cards);
        sortedCards.sort(Comparator.comparingInt(Card::getWeight));
        
        int consecutiveCount = 1;
        for (int i = 1; i < sortedCards.size(); i++) {
            if (sortedCards.get(i).getWeight() == sortedCards.get(i-1).getWeight() + 1) {
                consecutiveCount++;
                if (consecutiveCount >= 4) { // 有潜力形成顺子
                    score += consecutiveCount * 5;
                }
            } else {
                consecutiveCount = 1;
            }
        }
        
        return score;
    }

    // 获取游戏阶段倍数
    private static double getGameStageMultiplier(int gameStage) {
        switch (gameStage) {
            case EARLY_GAME:
                return 0.8; // 前期保守
            case MID_GAME:
                return 1.0;
            case LATE_GAME:
                return 1.3; // 后期激进
            default:
                return 1.0;
        }
    }

    // 获取角色倍数
    private static double getRoleMultiplier(boolean isLandlord, int handStrength) {
        if (isLandlord) {
            return handStrength > 80 ? 1.2 : 0.9; // 地主牌好就激进，牌差就保守
        } else {
            return handStrength > 80 ? 1.1 : 1.0; // 农民牌好也可以适当激进
        }
    }

    // 获取控制倍数
    private static double getControlMultiplier(List<Card> play, List<Card> lastPlayedCards) {
        if (lastPlayedCards == null || lastPlayedCards.isEmpty()) {
            return 1.0;
        }
        
        int playWeight = play.get(0).getWeight();
        int lastWeight = lastPlayedCards.get(0).getWeight();
        
        if (playWeight - lastWeight <= 2) {
            return 1.2; // 鼓励用较小的牌压制
        } else {
            return 0.8; // 不鼓励用大牌压小牌
        }
    }

    // 根据场上形势调整策略
    private static void adjustStrategyByGameSituation(Map<List<Card>, Double> playScores,
                                                    boolean isLandlord,
                                                    int gameStage,
                                                    int handStrength) {
        // 使用学习到的策略权重
        for (Map.Entry<List<Card>, Double> entry : playScores.entrySet()) {
            List<Card> play = entry.getKey();
            String strategy = determineStrategy(play, null, isLandlord);
            
            if (aiModel.strategyWeights.containsKey(strategy)) {
                double weight = aiModel.strategyWeights.get(strategy);
                entry.setValue(entry.getValue() * weight);
            }
            
            // 考虑平均剩余牌数
            if (aiModel.averageRemainingCards.containsKey(strategy)) {
                double avgRemaining = aiModel.averageRemainingCards.get(strategy);
                if (gameStage == LATE_GAME && avgRemaining < 5) {
                    entry.setValue(entry.getValue() * 1.3); // 后期优先考虑能快速出完的策略
                }
            }
        }
    }

    // 寻找最佳的跟牌
    private static List<Card> findBestFollowingCards(List<Card> handCards,
                                                     List<Card> lastPlayedCards,
                                                     boolean isLandlord,
                                                     int gameStage,
                                                     GameState gameState,
                                                     int handStrength) {
        // 如果是农民且上家是队友出的大牌，考虑不要
        if (!isLandlord && gameState.getLastPlayerId() != null &&
                !gameState.getLastPlayerId().equals(gameState.getLandlordId())) {
            if (CardUtil.getMaxWeight(lastPlayedCards) >= 14) {
                return Collections.emptyList();
            }
        }

        List<List<Card>> possiblePlays = findAllPossiblePlays(handCards, lastPlayedCards);
        if (possiblePlays.isEmpty()) {
            return Collections.emptyList();
        }

        // 使用学习到的策略权重评估每种出牌方案
        Map<List<Card>, Double> playScores = new HashMap<>();
        for (List<Card> play : possiblePlays) {
            double score = evaluatePlay(play, handCards, lastPlayedCards, isLandlord, gameStage, handStrength);
            playScores.put(play, score);
        }

        // 根据场上形势调整策略
        adjustStrategyByGameSituation(playScores, isLandlord, gameStage, handStrength);

        return playScores.entrySet().stream()
                .max(Map.Entry.comparingByValue())
                .map(Map.Entry::getKey)
                .orElse(possiblePlays.get(0));
    }

    // 其他必要的辅助方法...
    // 寻找所有可能的出牌组合
    private static List<List<Card>> findAllPossiblePlays(List<Card> cards) {
        List<List<Card>> possiblePlays = new ArrayList<>();

        // 添加单张
        cards.forEach(card -> possiblePlays.add(Collections.singletonList(card)));

        // 添加对子
        possiblePlays.addAll(CardUtil.findPairs(cards));

        // 添加三张
        possiblePlays.addAll(CardUtil.findTriples(cards));

        // 添加炸弹
        possiblePlays.addAll(CardUtil.findBombs(cards));

        // 如果有王炸，添加王炸
        if (CardUtil.hasRocket(cards)) {
            possiblePlays.add(CardUtil.findRocket(cards));
        }

        return possiblePlays;
    }

    // 根据上家出牌找到所有可能的跟牌
    private static List<List<Card>> findAllPossiblePlays(List<Card> cards, List<Card> lastPlayedCards) {
        CardPatternUtil.CardPattern lastPattern = CardPatternUtil.getPattern(lastPlayedCards);
        List<List<Card>> possiblePlays = new ArrayList<>();

        // 根据上家的牌型找到所有可能的跟牌
        switch (lastPattern) {
            case SINGLE:
                cards.stream()
                        .filter(card -> card.getWeight() > lastPlayedCards.get(0).getWeight())
                        .forEach(card -> possiblePlays.add(Collections.singletonList(card)));
                break;
            case PAIR:
                CardUtil.findPairs(cards).stream()
                        .filter(pair -> pair.get(0).getWeight() > lastPlayedCards.get(0).getWeight())
                        .forEach(possiblePlays::add);
                break;
            case TRIPLE:
                CardUtil.findTriples(cards).stream()
                        .filter(triple -> triple.get(0).getWeight() > lastPlayedCards.get(0).getWeight())
                        .forEach(possiblePlays::add);
                break;
            // ... 其他牌型的处理 ...
        }

        // 可以用炸弹
        possiblePlays.addAll(CardUtil.findBombs(cards));

        // 可以用王炸
        if (CardUtil.hasRocket(cards)) {
            possiblePlays.add(CardUtil.findRocket(cards));
        }

        return possiblePlays;
    }
    public static int calculateHandStrength(List<Card> cards) {
        int strength = 0;
        Map<String, List<Card>> rankGroups = CardUtil.groupByRank(cards);

        // 计算大牌分数
        strength += calculateBigCardScore(cards, rankGroups);

        // 计算炸弹和三张分数
        strength += calculateBombAndTripleScore(rankGroups);

        // 计算牌型齐度
        strength += calculatePatternScore(cards);

        // 根据手牌数量调整分数
        if (cards.size() < 16) {
            strength = (int)(strength * 0.8);
        }

        return strength;
    }

    // 计算大牌分数
    private static int calculateBigCardScore(List<Card> cards, Map<String, List<Card>> rankGroups) {
        int score = 0;
        
        // 计算2和大小王的分数
        for (Card card : cards) {
            if (card.getRank().equals("2")) {
                score += 6;
            } else if (card.getSuit() == Card.Suit.JOKER) {
                score += (card.getRank().equals("BIG") ? 10 : 8);
            } else if (card.getRank().equals("A")) {
                score += 4;
            } else if (card.getRank().equals("K")) {
                score += 3;
            }
        }
        
        return score;
    }
    
    // 计算炸弹和三张的分数
    private static int calculateBombAndTripleScore(Map<String, List<Card>> rankGroups) {
        int score = 0;
        
        for (List<Card> cards : rankGroups.values()) {
            if (cards.size() == 4) {  // 炸弹
                score += 20;
            } else if (cards.size() == 3) {  // 三张
                score += 10;
            }
        }
        
        // 检查是否有王炸
        if (rankGroups.containsKey("JOKER") && rankGroups.get("JOKER").size() == 2) {
            score += 30;
        }
        
        return score;
    }
    
    // 计算牌型整齐度分数
    private static int calculatePatternScore(List<Card> cards) {
        int score = 0;
        Map<String, Integer> rankCounts = new HashMap<>();
        
        // 统计每个点数的数量
        for (Card card : cards) {
            rankCounts.merge(card.getRank(), 1, Integer::sum);
        }
        
        // 检查连续的单张
        List<String> sortedRanks = new ArrayList<>(rankCounts.keySet());
        sortedRanks.sort((a, b) -> {
            int weightA = Card.getWeightByRank(a);
            int weightB = Card.getWeightByRank(b);
            return weightA - weightB;
        });
        
        int consecutiveCount = 1;
        for (int i = 1; i < sortedRanks.size(); i++) {
            int prevWeight = Card.getWeightByRank(sortedRanks.get(i-1));
            int currWeight = Card.getWeightByRank(sortedRanks.get(i));
            if (currWeight == prevWeight + 1) {
                consecutiveCount++;
                if (consecutiveCount >= 5) {  // 顺子
                    score += consecutiveCount * 2;
                }
            } else {
                consecutiveCount = 1;
            }
        }
        
        // 检查对子和连对
        int pairCount = 0;
        for (int count : rankCounts.values()) {
            if (count == 2) {
                pairCount++;
                score += 2;
            }
        }
        
        // 如果有3个或更多对子，额外加分
        if (pairCount >= 3) {
            score += pairCount * 2;
        }
        
        return score;
    }

    private static void updateStrategyIfNeeded() {
        long currentTime = System.currentTimeMillis();
        if (currentTime - lastUpdateTime > UPDATE_INTERVAL) {
            // 从 AITrainer 获取最新的策略权重
            Map<String, Double> newWeights = AITrainer.getStrategyWeights();
            Map<String, Double> newCardPatterns = AITrainer.getAverageRemainingCards();
            
            if (newWeights != null && !newWeights.isEmpty()) {
                aiModel.strategyWeights = newWeights;
            }
            if (newCardPatterns != null && !newCardPatterns.isEmpty()) {
                aiModel.averageRemainingCards = newCardPatterns;
            }
            
            lastUpdateTime = currentTime;
            logger.debug("AI策略已更新");
        }
    }

    /**
     * 确定出牌策略类型
     * @param playedCards 要出的牌
     * @param lastPlayedCards 上家出的牌
     * @param isLandlord 是否是地主
     * @return 策略标识符
     */
    public static String determineStrategy(List<Card> playedCards, List<Card> lastPlayedCards, boolean isLandlord) {
        if (playedCards == null || playedCards.isEmpty()) {
            return "PASS";
        }
        
        String baseStrategy = CardPatternUtil.getPattern(playedCards).name();
        String role = isLandlord ? "LANDLORD" : "FARMER";
        return role + "_" + baseStrategy;
    }

    // 评估出牌节奏
    private static double evaluateRhythm(List<Card> play, List<Card> remainingCards) {
        double rhythmScore = 1.0;
        
        // 检查是否保持了良好的出牌节奏
        CardPatternUtil.CardPattern pattern = CardPatternUtil.getPattern(play);
        Map<String, List<Card>> remainingGroups = CardUtil.groupByRank(remainingCards);
        
        // 如果出单张，检查是否还有更多单张可以连续出
        if (pattern == CardPatternUtil.CardPattern.SINGLE) {
            int singleCount = (int) remainingGroups.values().stream()
                    .filter(group -> group.size() == 1)
                    .count();
            if (singleCount > 0) {
                rhythmScore *= 1.2; // 鼓励连续出单张
            }
        }
        
        // 如果出对子，检查是否还有更多对子可以连续出
        if (pattern == CardPatternUtil.CardPattern.PAIR) {
            int pairCount = (int) remainingGroups.values().stream()
                    .filter(group -> group.size() == 2)
                    .count();
            if (pairCount > 0) {
                rhythmScore *= 1.2; // 鼓励连续出对子
            }
        }
        
        return rhythmScore;
    }

    // 评估牌型灵活性
    private static double evaluateFlexibility(List<Card> remainingCards) {
        double flexibilityScore = 1.0;
        Map<String, List<Card>> rankGroups = CardUtil.groupByRank(remainingCards);
        
        // 计算不同牌型的数量
        int singleCount = 0;
        int pairCount = 0;
        int tripleCount = 0;
        
        for (List<Card> group : rankGroups.values()) {
            switch (group.size()) {
                case 1: singleCount++; break;
                case 2: pairCount++; break;
                case 3: tripleCount++; break;
            }
        }
        
        // 根据牌型组合的多样性评分
        int patternTypes = 0;
        if (singleCount > 0) patternTypes++;
        if (pairCount > 0) patternTypes++;
        if (tripleCount > 0) patternTypes++;
        
        flexibilityScore *= (1.0 + patternTypes * 0.1); // 牌型越多样，分数越高
        
        return flexibilityScore;
    }

    // 评估关键牌
    private static double evaluateKeyCards(List<Card> play, 
                                         List<Card> remainingCards,
                                         boolean isLandlord,
                                         int gameStage) {
        double keyCardScore = 1.0;
        
        // 检查是否保留了关键牌
        boolean hasRocket = CardUtil.hasRocket(remainingCards);
        boolean hasBomb = !CardUtil.findBombs(remainingCards).isEmpty();
        
        // 在不同游戏阶段对关键牌的评估
        if (gameStage == EARLY_GAME) {
            // 早期阶段，保留炸弹和火箭更有价值
            if (hasRocket) keyCardScore *= 1.3;
            if (hasBomb) keyCardScore *= 1.2;
        } else if (gameStage == LATE_GAME) {
            // 后期阶段，使用炸弹和火箭更有价值
            if (CardUtil.hasRocket(play)) keyCardScore *= 1.5;
            if (CardPatternUtil.getPattern(play) == CardPatternUtil.CardPattern.BOMB) {
                keyCardScore *= 1.4;
            }
        }
        
        // 地主和农民的不同策略
        if (isLandlord) {
            // 地主更倾向于保留大牌
            if (hasHighCards(remainingCards)) keyCardScore *= 1.2;
        } else {
            // 农民更倾向于配合队友
            if (hasControlCards(remainingCards)) keyCardScore *= 1.1;
        }
        
        return keyCardScore;
    }

    // 检查是否有大牌
    private static boolean hasHighCards(List<Card> cards) {
        return cards.stream().anyMatch(card -> card.getWeight() >= 14); // A及以上
    }

    // 检查是否有控制牌
    private static boolean hasControlCards(List<Card> cards) {
        Map<String, List<Card>> rankGroups = CardUtil.groupByRank(cards);
        return rankGroups.values().stream()
                .anyMatch(group -> group.size() >= 3); // 三张或更多
    }
}